package com.ruoyi.mtg.controller;

import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.mtg.domain.CardData;
import com.ruoyi.mtg.service.ICardDataService;
import com.ruoyi.mtg.service.IMtgService;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Controller
@RequestMapping("/mtg")
public class MtgController extends BaseController {

    @Autowired
    ICardDataService cardDataService;

    @Autowired
    IMtgService mtgService;

    public String prefix = "mtg";

    @GetMapping("/deckQuery")
    public String toDeckQuery() {
        return prefix + "/deckQuery";
    }

    @PostMapping("/deckQuery")
    @ResponseBody
    public AjaxResult deckQuery(String deckStr) {
        if (StrUtil.isEmpty(deckStr)) {
            throw new RuntimeException("deckStr is empty");
        }

        Pattern p = Pattern.compile("^(\\d+)\\s+(.+?)(\\s+\\((.+?)\\)\\s+(\\d+))?$");
        List<RCardData> cards = Arrays.stream(deckStr.split("\n"))
                .filter(StrUtil::isNotEmpty)
                .map(String::trim)
                .filter(s -> !s.equalsIgnoreCase("Deck"))
                .filter(s -> !s.equalsIgnoreCase("Sideboard"))
                .map(s -> ReUtil.isMatch(p, s)
                        ? new RCardData().setFound(true).setStr(s)
                        : new RCardData().setFound(false).setStr(s).setCardData(new CardData().setName(s).setText("!!NOT MATCH")))
                .peek(r -> {
                    if (r.found) {
                        List<String> g = ReUtil.getAllGroups(p, r.getStr());
                        Objects.requireNonNull(g);
                        r.setCnt(Integer.parseInt(g.get(1)))
                                .setName(g.get(2))
                                .setSetcode(g.get(4))
                                .setSetNo(StrUtil.isEmpty(g.get(5)) ? null : Integer.parseInt(g.get(5)));

                        String[] qryNames = r.getName().split("//"); //  eg: "Find // Finality"
                        List<CardData> resDatas = Arrays.stream(qryNames)
                                .map(s -> s.replaceAll("^\\s+", ""))
                                .map(s -> s.replaceAll("\\s+$", ""))
                                .map(s -> cardDataService.getOne(new QueryWrapper<CardData>().eq("name", s)))
                                .collect(Collectors.toList());
                        if (resDatas.isEmpty()) {
                            r.setFound(false);
                        } else {
                            CardData main = resDatas.get(0);
                            if (resDatas.size() != 1) {
                                List<CardData> others = resDatas.subList(1, resDatas.size());
                                main.setOthers(others);
                            }
                            r.setCardData(main);
                        }
                        log.debug("{} => {}", r.getName(), r.getCardData());
                    }
                })
                .collect(Collectors.toList());
        cards = sortCards(cards);
        return AjaxResult.success(cards);
    }

    public List<RCardData> sortCards(List<RCardData> datas) {
        return datas.stream().sorted((o1, o2) -> {
            if (o1.getCardData() == null || o2.getCardData() == null) {
                return -1;
            }
            int n = calcCardTypeScore(o2) - calcCardTypeScore(o1);
            if (n == 0) {
                n = o1.getCardData().getConvertedManaCost().subtract(o2.getCardData().getConvertedManaCost()).intValue();
            }
            if (n == 0) {
                n = o1.getCardData().getName().compareTo(o2.getCardData().getName());
            }
            return n;
        }).collect(Collectors.toList());
    }

    public int calcCardTypeScore(RCardData rc) {
        String type = rc.getCardData().getType().toLowerCase();
        if (type.contains("planeswalker")) {
            return 100;
        } else if (type.contains("creature")) {
            return 90;
        } else if (type.contains("artifact")) {
            return 80;
        } else if (type.contains("instant")) {
            return 70;
        } else if (type.contains("sorcery")) {
            return 60;
        } else if (type.contains("enchantment")) {
            return 50;
        } else if (type.contains("land")) {
            return 10;
        } else {
            return 0;
        }
    }

    @Data
    @Accessors(chain = true)
    public static class RCardData {
        String str;
        boolean found;

        int cnt;
        String name;
        String setcode;
        Integer setNo;
        CardData cardData;
    }

    @GetMapping("/icon")
    public String icon() {
        return prefix + "/icon";
    }



}
